<template>
  <demo-content :title="title">
    <p>
      贝塞尔曲线(bezier curve)最初是由法国物理学家与数学家Paul de Casteljau
      发明的, 它的广泛运用要归功于法国工程师皮埃尔.贝塞尔。
      贝塞尔曲线起初被用在汽车车身的设计上，现在则多用于计算机图形系统之中，
      例如Adobe Illustrator、Apple的Cocoa 框架以及HTMLS的Canvas。
    </p>
    <p>
      贝塞尔曲线分为两种:平方 (quadratic)贝塞尔曲线及立方 (cubic)贝塞尔曲线。
      平方贝塞尔曲线是一种二次曲线(second degree
      curve)，这种曲线由三个点来定义，两个锚点(anchor point),
      以及一个控制点(control point)。
    </p>
    <p>
      通过
      <code>
        quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void;
      </code>
      绘制二次贝塞尔曲线，该函数前两个参数是控制点的坐标，后两个参数是第二个锚点的坐标。第一个锚点坐标为
      moveTo 或者 lineTo 等上一个绘制操作的结束点确定。
    </p>
    <p>
      而立方贝塞尔曲线则是一种三次曲线(third-degree curve), 是由四个点来控制的,
      两个锚点及两个控制点。
    </p>
    <canvas ref="canvasRef" width="600" height="400"></canvas>
  </demo-content>
</template>

<script setup lang="ts">
import { onMounted, ref } from "vue";
import {
  DrawingSurfaceHelper,
  Point,
  clientPosCvt,
  ellipse,
  line,
} from "./utils";

const title = "二次贝塞尔曲线";
// 指定组件上的属性
defineOptions({ title });

const canvasRef = ref<HTMLCanvasElement>();
onMounted(() => {
  const canvas = canvasRef.value!;
  const ctx = canvas.getContext("2d")!;
  let firstAnchor: Point | null = null;
  let secondAnchor: Point | null = null;
  let firstControl: Point | null = null;
  const dsHelper1 = DrawingSurfaceHelper.create(ctx);
  const dsHelper2 = DrawingSurfaceHelper.create(ctx);
  const r = 3;
  function drawPos(pos: Point, fillStyle: string) {
    ellipse.draw(ctx, { ...pos, radiusX: r, fillStyle });
  }
  const drawFirstAnchor = (p?: Point) => drawPos(p || firstAnchor!, "red");
  const drawSecondAnchor = (p?: Point) => drawPos(p || secondAnchor!, "green");
  const drawFirstControl = (p?: Point) => drawPos(p || firstControl!, "blue");

  canvas.onmousedown = (e: MouseEvent) => {
    if (!firstAnchor) {
      firstAnchor = clientPosCvt(ctx, e);
      drawFirstAnchor();
      dsHelper1.takeSnapshot();
    } else if (!secondAnchor) {
      secondAnchor = clientPosCvt(ctx, e);
      dsHelper1.restoreSnapshot();
      drawSecondAnchor();
      dsHelper2.takeSnapshot();
      const { x: x1, y: y1 } = firstAnchor;
      const { x: x2, y: y2 } = secondAnchor;
      line.draw(ctx, { x1, y1, x2, y2 });
    } else if (!firstControl) {
      firstAnchor = secondAnchor = firstControl = null;
    }
  };
  canvas.onmousemove = (e: MouseEvent) => {
    if (!firstAnchor) return;
    if (!secondAnchor) {
      dsHelper1.restoreSnapshot();
      const pos = clientPosCvt(ctx, e);
      const { x: x1, y: y1 } = firstAnchor;
      const { x: x2, y: y2 } = pos;
      line.draw(ctx, { x1, y1, x2, y2 });
      drawSecondAnchor(pos);
    } else {
      dsHelper2.restoreSnapshot();
      const pos = clientPosCvt(ctx, e);
      drawFirstControl(pos);
      ctx.beginPath();
      ctx.moveTo(firstAnchor.x, firstAnchor.y);
      ctx.quadraticCurveTo(pos.x, pos.y, secondAnchor.x, secondAnchor.y);
      ctx.stroke();
    }
  };
});
</script>

<style src="./default.css" scoped></style>
